﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using SCG.General;
using SCG.SolarVengeanceEngine;
using System.IO;

namespace SCG.SolarVengeance
{
    public partial class SetupPage : BasePage
    {
        //constructors
        public SetupPage()
            : base()
        {
            InitializeComponent();
        }

        //set the game mode - called prior to Initialize
        private GameMode _gameMode;
        public GameMode GameMode
        {
            get
            {
                return _gameMode;
            }
            set
            {
                _gameMode = value;
                switch (_gameMode)
                {
                    case GameMode.Solo:
                        numPlayers.Enabled = false;
                        if (numPlayers.Value < 1)
                            numPlayers.Value = 1;
                        numPlayers.Minimum = 1;
                        if (numBrain.Value < 1)
                            numBrain.Value = 1;
                        numBrain.Minimum = 1;
                        break;
                    case GameMode.BrainDuel:
                        numPlayers.Enabled = false;
                        numPlayers.Minimum = 0;
                        numPlayers.Value = 0;
                        if (numBrain.Value < 2)
                            numBrain.Value = 2;
                        numBrain.Minimum = 2;
                        break;
                    case GameMode.Multiplayer:
                        numPlayers.Enabled = true;
                        if (numPlayers.Value < 2)
                            numPlayers.Value = 2;
                        numPlayers.Minimum = 2;
                        numBrain.Minimum = 0;
                        numBrain.Value = 0;
                        break;
                }

                //show unauthorized scenario warning?
                if (GameMode == GameMode.Multiplayer)
                {
                    lvScenarios.StateImageList = stateImages;
                    foreach (ListViewItem lvi in lvScenarios.Items)
                    {
                        Scenario scen = lvi.Tag as Scenario;
                        if (MainForm.GetAuthorizedScenario(scen.Name) == null)
                            lvi.StateImageIndex = 0;
                        else
                            lvi.StateImageIndex = -1;
                    }
                }
                else
                    lvScenarios.StateImageList = null;
            }
        }

        //initialization
        public override void Initialize()
        {
            if (lvScenarios.Items.Count == 0)
            {
                //load scenarios
                lvScenarios.BeginUpdate();
                foreach (Scenario scenario in MainForm.TitlePage.Scenarios)
                {
                    ListViewItem lvi = lvScenarios.Items.Add(scenario.DisplayName);
                    lvi.Tag = scenario;
                    if (scenario.Name == "Classic")
                        lvi.Selected = true;
                    Image preview = MainForm.TitlePage.PreviewImages[scenario];
                    imgPreview.Images.Add(preview);
                    lvi.ImageIndex = lvScenarios.Items.Count - 1;
                }
                lvScenarios.EndUpdate();

                //load brains
                foreach (Brain brain in MainForm.TitlePage.Brains)
                {
                    _masterBrainList.Add(brain);
                    if (brain.DevelopmentMode)
                        cbIncludeDevBrain.Visible = true;
                }

                //ensure scenarios are flagged first time through
                GameMode = GameMode;
            }
        }

        //the selected scenario
        private Scenario _scenario;
        public Scenario Scenario
        {
            get
            {
                return _scenario;
            }
        }

        //number of players
        public int HumanPlayers
        {
            get
            {
                return (int)numPlayers.Value;
            }
        }
        public int BrainPlayers
        {
            get
            {
                return (int)numBrain.Value;
            }
        }

        //capital values
        public int CapitalValues
        {
            get
            {
                if (Scenario.UsesCapitals)
                    return (int)numCapitalValue.Value;
                else
                    return 20;
            }
        }

        //starting resources
        public int StartingResources
        {
            get
            {
                if (Scenario.UsesCapitals)
                    return (int)numCapitalResources.Value;
                else
                    return 100;
            }
        }

        //brain challenge level
        public ChallengeLevel ChallengeLevel
        {
            get
            {
                return (ChallengeLevel)trackChallenge.Value;
            }
        }

        //get a brain by name
        public Brain GetBrain(string name)
        {
            foreach (Brain brain in _masterBrainList)
                if (brain.BrainName == name)
                    return brain;
            return null;
        }

        //get a list of brains with the minimum challenge level
        public List<Brain> GetBrainList(int num)
        {
            if (num <= 0)
                return null;

            bool hasDevBrain = false;
            List<Brain> lst = new List<Brain>();
            ChallengeLevel maxCL = ChallengeLevel.Training;
            do
            {
                hasDevBrain = false;
                lst.Clear();
                for (int n = 0; n < num; n++)
                {
                    lst.Add(_masterBrainList.RandomValue);
                    if (lst[lst.Count - 1].DevelopmentMode)
                        hasDevBrain = true;
                }
                maxCL = ChallengeLevel.Training;
                foreach (Brain brain in lst)
                {
                    if (brain.Challenge > maxCL)
                        maxCL = brain.Challenge;
                }
            }
            while (maxCL != ChallengeLevel);

            if (cbIncludeDevBrain.Checked)
            {
                if (!hasDevBrain)
                {
                    lst.RemoveAt(0);
                    Brain devBrain = _masterBrainList.RandomValue;
                    while (!devBrain.DevelopmentMode)
                        devBrain = _masterBrainList.RandomValue;
                    lst.Add(devBrain);
                }
            }

            return lst;
        }

        //selected a scenario, update preview
        private int ctlY;
        private NumericUpDown numCapitalValue;
        private NumericUpDown numCapitalResources;
        private Scenario scenario;
        private bool _settingValues = false;
        private void lvScenarios_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lvScenarios.SelectedItems.Count != 1)
                return;

            //display scenario description
            scenario = (Scenario)lvScenarios.SelectedItems[0].Tag;
            _scenario = scenario;

            //use authorized version in MP games to avoid hacking games
            if (GameMode == GameMode.Multiplayer)
            {
                Scenario authorized = MainForm.GetAuthorizedScenario(scenario.Name);
                if (authorized != null)
                    _scenario = authorized;
            }

            lblScenName.Text = scenario.DisplayName;
            lblDescription.Text = scenario.Description;

            //enforce maximums
            _settingValues = true;
            int minHumans = 1;
            if (GameMode == GameMode.BrainDuel)
                minHumans = 0;
            else if (GameMode == GameMode.Multiplayer)
                minHumans = 2;
            int maxBrains = scenario.MaxPlayers - minHumans;
            if (numBrain.Value > maxBrains)
                numBrain.Value = maxBrains;
            numBrain.Maximum = maxBrains;
            if (numBrain.Value < numBrain.Minimum)
                numBrain.Value = numBrain.Minimum;

            //remove previously generated controls
            for (int n = pnlParameters.Controls.Count - 1; n > 3; n--)
            {
                Control ctl = pnlParameters.Controls[n];
                if (ctl.Tag != null)
                {
                    NumericUpDown num = ctl as NumericUpDown;
                    num.ValueChanged -= changeParameterValue;
                }
                pnlParameters.Controls.RemoveAt(n);
            }

            //use capitals?
            ctlY = lblBrain.Top + (lblBrain.Top - lblHuman.Top);
            if (scenario.UsesCapitals)
            {
                numCapitalValue = GenerateControl("Capital Values", 0, 100, 1, null);
                if (scenario.DefaultCapitalValue > 100)
                    numCapitalValue.Maximum = scenario.DefaultCapitalValue;
                numCapitalValue.Value = scenario.DefaultCapitalValue;
                numCapitalResources = GenerateControl("Capital Resources", 0, 10000, 10, null);
                if (scenario.DefaultCapitalResources > 10000)
                    numCapitalResources.Maximum = scenario.DefaultCapitalResources;
                numCapitalResources.Value = scenario.DefaultCapitalResources;
            }

            //scenario parameters
            foreach (ScenarioParameter sp in scenario.Parameters)
            {
                NumericUpDown num = GenerateControl(sp.Name, sp.MinValue, sp.MaxValue, 1, sp);
                string entryName = scenario.Name + ":" + sp.Name;
                num.Value = MainForm.Settings.Get(entryName, sp.DefaultValue);
                sp.Value = (int)num.Value;
                num.ValueChanged += changeParameterValue;
            }
            _settingValues = false;

            //preview image
            UpdatePreview();
        }
        private NumericUpDown GenerateControl(string text, int min, int max, int increment, object tag)
        {
            Label lbl = new Label();
            lbl.Text = text;
            lbl.Font = lblHuman.Font;
            lbl.ForeColor = lblHuman.ForeColor;
            lbl.Location = new Point(lblHuman.Left, ctlY);
            lbl.AutoSize = true;
            pnlParameters.Controls.Add(lbl);
            NumericUpDown num = new NumericUpDown();
            num.Minimum = min;
            num.Maximum = max;
            num.Increment = increment;
            num.Font = numPlayers.Font;
            num.BackColor = numPlayers.BackColor;
            num.ForeColor = numPlayers.ForeColor;
            num.Tag = tag;
            num.Location = new Point(numPlayers.Left, ctlY);
            num.Size = numPlayers.Size;
            pnlParameters.Controls.Add(num);
            ctlY += (lblBrain.Top - lblHuman.Top);
            return num;
        }

        //parameter value changed, update preview
        private void changeParameterValue(object sender, EventArgs e)
        {
            if (_settingValues)
                return;
            NumericUpDown num = sender as NumericUpDown;
            if (num.Tag != null)
            {
                ScenarioParameter sp = num.Tag as ScenarioParameter;
                sp.Value = (int)num.Value;
            }
            UpdatePreview();
        }
        private void UpdatePreview()
        {
            if (scenario == null)
                return;
            SVGame dummy = new SVGame(null);
            try
            {
                scenario.BuildScenaio(dummy, null, (int)(numPlayers.Value + numBrain.Value), 20, 100, MainForm);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error generating Scenario: " + ex.Message);
            }
            preview.Game = dummy;
        }

        //cancel
        private void btnCancel_Click(object sender, EventArgs e)
        {
            if (GameMode == GameMode.Multiplayer)
                MainForm.ShowPage(Pages.Lobby);
            else
                MainForm.ShowPage(Pages.Title);
        }

        //proceed
        private void btnProceed_Click(object sender, EventArgs e)
        {
            MainForm.Settings.Set("Challenge", (int)ChallengeLevel);

            //also remember scenario settings
            foreach (ScenarioParameter sp in scenario.Parameters)
            {
                string entryName = scenario.Name + ":" + sp.Name;
                MainForm.Settings.Set(entryName, sp.Value);
            }
            MainForm.Settings.SaveSettings();

            //solo or multi?
            if (GameMode == GameMode.Multiplayer)
            {
                Scenario authorized = MainForm.GetAuthorizedScenario(scenario.Name);
                if (authorized == null)
                    if (MessageBox.Show("This is a custom Scenario, and any others who join will need to have the Scenario file.  Proceed?", "Custom Scenario", MessageBoxButtons.YesNo) == DialogResult.No)
                        return;
                string roomName = scenario.Name + ";" + MainForm.Prism.ThisUser.UserName + ";" + HumanPlayers + ";" +
                    BrainPlayers + ";";
                foreach (ScenarioParameter sp in scenario.Parameters)
                    roomName += sp.Value + ";";
                MainForm.Prism.CreateRoom(roomName, HumanPlayers);
                MainForm.ShowPage(Pages.Lobby);
            }
            else
                MainForm.KickoffGame();
        }

        //make sizes work
        private void SetupPage_Load(object sender, EventArgs e)
        {
            column.Width = lvScenarios.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth - 4;
            trackChallenge.Value = MainForm.Settings.Get("Challenge", 1);
        }

        private void lblHuman_Click(object sender, EventArgs e)
        {
            numCapitalResources.Height++;
            numCapitalResources.Width++;
            MessageBox.Show(numCapitalResources.Height + "");
        }

        //change brain difficulty
        private void trackChallenge_ValueChanged(object sender, EventArgs e)
        {
            lblChallengeLevel.Text = ChallengeLevel.ToString();
            switch (ChallengeLevel)
            {
                case ChallengeLevel.Training:
                    lblChallengeLevel.ForeColor = Color.Lime;
                    break;
                case ChallengeLevel.Easy:
                    lblChallengeLevel.ForeColor = Color.Aqua;
                    break;
                case ChallengeLevel.Moderate:
                    lblChallengeLevel.ForeColor = Color.Yellow;
                    break;
                case ChallengeLevel.Difficult:
                    lblChallengeLevel.ForeColor = Color.Orange;
                    break;
                default:
                    lblChallengeLevel.ForeColor = Color.Red;
                    break;
            }
        }

        //private members
        private RandomList<Brain> _masterBrainList = new RandomList<Brain>();
    }

    //setup mode
    public enum GameMode { Solo, Multiplayer, BrainDuel }
}
